# -*- coding: utf-8 -*-
# @Time: 2021/2/27 10:13
# @Auhtor: gilbert(靜靜)
# @File： report_bro.py
# @Softeware: PyCharm

from odoo import models, fields, _, tools
from odoo.exceptions import UserError
from odoo.tools.safe_eval import safe_eval
from odoo.addons.odoo_report_bro.controllers.main import ReportBroControllers
import json, sys, os, jinja2, random, base64
from odoo.addons.odoo_report_bro.libs.data_proxy import DataModelProxy

if hasattr(sys, 'frozen'):
    # When running on compiled windows binary, we don't have access to package loader.
    path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', 'html'))
    loader = jinja2.FileSystemLoader(path)
else:
    loader = jinja2.PackageLoader('odoo.addons.odoo_report_bro', "demos")
jinja_env = jinja2.Environment('<%', '%>', '${', '}', loader=loader, autoescape=True)


#
# class ReportBroModelFields(models.Model):
#     _name = 'report.bro.model.fields'
#     model_id = fields.Many2one('ir.model', string='Model')
#     filed_ids = fields.Many2many('ir.model.fields', 'report_bro_fields_rel', 'report_bro_id', 'field_id',
#                                  string='Fields')
#     name = fields.Char(string='Model Name')


class ReportBro(models.Model):
    _name = 'report.bro'
    name = fields.Char(u'Name')
    key = fields.Char(u'Key', readonly=True)
    report_definition = fields.Char(u'Report Definition', readonly=False)
    data = fields.Char(u'Data', readonly=True)
    is_test_data = fields.Boolean('Is Test Data', readonly=True)
    pdf_file = fields.Binary('Pdf File', readonly=True)
    pdf_file_size = fields.Integer('Pdf File Size', readonly=True)
    model_id = fields.Many2one('ir.model', string='Model')
    # model_filed_ids = fields.Many2many('report.bro.model.fields', 'report_bro_model_fields_rel', 'report_bro_id',
    #                                    'mode_field_id', string='Model Fields')
    is_show_model = fields.Boolean(u'Show All Field')
    pageFormat = fields.Char(u'pageFormat', default='A5')
    orientation = fields.Selection([('portrait', 'Portrait'), ('horizontal', 'Horizontal')], string=u'orientation',
                                   default='portrait')
    marginLeft = fields.Char(u'marginLeft', default='10')
    marginTop = fields.Char(u'marginTop', default='10')
    marginRight = fields.Char(u'marginRight', default='10')
    marginBottom = fields.Char(u'marginBottom', default='10')
    headerSize = fields.Char(u'headerSize', default=0)
    header = fields.Char(u'header', default='false')
    headerDisplay = fields.Char(u'headerDisplay', default='always')

    footerSize = fields.Char(u'footerSize', default='0')
    footer = fields.Char(u'footer', default='false')
    footerDisplay = fields.Char(u'footerDisplay', default='always')

    def design_report(self):
        if not self.model_id:
            raise UserError(u'请选择模型！')
        action = {
            'name': 'FEC',
            'type': 'ir.actions.act_url',
            'url': "/reportbro/design/" + str(self.id),
            'target': 'new',
        }
        return action

    def get_child_line(self, model_row, field_row):
        json_data = {}
        for field_name in dir(model_row):
            if not self.env[model_row._name]._fields.get(field_name, False):
                continue
            if field_row.type == 'many2one' and field_name not in ['name', 'display_name']:
                continue
            file_row = self.env[model_row._name]._fields.get(field_name)
            convert_to_export = file_row.convert_to_export
            try:
                val = convert_to_export(model_row[field_name], model_row)
            except Exception as exception:
                val = ''
            if file_row.type in ['one2many', 'many2many']:
                json_data.update({field_name: []})
            elif file_row.type in ['many2one']:
                json_data.update({field_name: self.get_child_line( model_row[field_name],file_row)})
            elif file_row.type in ['binary'] and model_row[field_name] and isinstance(model_row[field_name], bytes):
                # print(field_name, base64.encodestring(model_row[field_name]))
                json_data.update({field_name: base64.encodestring(model_row[field_name])})
            else:
                json_data.update({field_name: str(val or '')})
        return json_data

    def get_report_data(self, model_row):
        json_data = {}
        for field_name in dir(model_row):
            if not self.env[model_row._name]._fields.get(field_name):
                continue
            field_row = self.env[model_row._name]._fields.get(field_name)
            convert_to_export = field_row.convert_to_export

            val = convert_to_export(model_row[field_name], model_row)
            if field_row.type in ['one2many', 'many2many']:
                list_val = []
                if not model_row[field_name]:
                    list_val = [self.get_default_field_val(model_row[field_name])]
                for field_child_name in model_row[field_name]:
                    return_val = self.get_child_line(field_child_name, field_row)
                    if return_val: list_val.append(return_val)
                json_data.update({field_name: list_val})
            elif field_row.type in ['many2one']:
                if not model_row[field_name]:
                    json_data.update({field_name: self.get_default_field_val(model_row[field_name])})
                for field_child_name in model_row[field_name]:
                    json_data.update({field_name: self.get_child_line(field_child_name, field_row) or {}} )
            elif field_row.type in ['binary'] and model_row[field_name] and isinstance(model_row[field_name], bytes):
                json_data.update({field_name: model_row[field_name]})
            elif field_row.type in ['float', 'int', 'monetary']:
                json_data.update({field_name: str(val or 0)})
            elif field_row.type in ['date']:
                json_data.update({field_name: str(val)})
            elif field_row.type in ['datetime'] and val:
                json_data.update({field_name: str(val)[:10]})
            elif field_row.type in ['boolean']:
                json_data.update({field_name: val and '是' or '否'})
            else:
                json_data.update({field_name: '%s' % str(val)})
        return json_data

    def get_default_field_val(self, model_row):
        return_val = {}
        for field_name in dir(model_row):
            if not self.env[model_row._name]._fields.get(field_name):
                continue
            return_val.update({field_name: ''})
        return return_val

    def preview_report(self):
        if not self.report_definition:
            raise UserError(u'未保存设计不能进行预览！')
        model_row = self.env[self.model_id.model].sudo().search([], limit=1)
        self.env['res.company'].search([], limit=1)
        report_data = self.get_report_data(model_row and model_row[0])
        print(report_data)
        json_data = {
            'report': json.loads(self.report_definition),
            'outputFormat': 'pdf',
            'data': report_data,
            'isTestData': True,
        }
        key = ReportBroControllers().reportbro_report_run_put_method(json_data)

        action = {
            'name': 'FEC',
            'type': 'ir.actions.act_url',
            'url': "/reportbro/report/run?" + key.replace(':', '=') + "&outputFormat=pdf",
            'target': 'new',
        }
        return action

    def design_new(self):
        self.report_definition = False
        # all_list = [
        #     ('0001', '混棉'),
        #     ('0002', '清花'),
        #     ('0003_1', '配料车间_今日工作计划'),
        #     ('0003_2', '配料车间_需要打小样的订单5天内'),
        #     ('0003_3', '配料车间_并条已完工，等待检测放行的订单'),
        #     ('0003_4', '配料车间_今日已放行粗纱的订单'),
        #     ('0004_1', '细纱_今日工作计划'),
        #     ('0004_2', '细纱_今日细纱投产'),
        #     ('0005_1', '自络_今日工作计划'),
        #     ('0005_2', '自络_今日细纱投产'),
        #     ('0006_1', '并条粗纱_今日工作计划'),
        #     ('0006_2', '并条粗纱_待放行的订单'),
        #     ('0006_3', '并条粗纱_已放行当是未投产粗纱的订单'),
        #     ('0006_4', '并条粗纱_最近放行且投产粗纱的订'),
        # ]
        # product_list = self.env['product.template'].search([])
        # for key, val in all_list:
        #     for index in range(random.randint(18, 29)):
        #         self.env['fhboard.tbhlyqhgzjh'].sudo().create({
        #             'fhplan_date': str(fields.Datetime.today())[0:10],
        #             'fhvarieties': product_list[index].id,
        #             'fhorder_number': index * 100,
        #             'fhbatch': key + "10086",
        #             'fhdelivery_date': str(fields.Datetime.today())[0:10],
        #             'fhworkshop': key,
        #             'fhput_date': str(fields.Datetime.today())[0:10],
        #             'fhquantity': index * 10,
        #             'fhtype': key,
        #         })
        #     #
        return True
        # return True

    def get_field_dict(self, model_row, field_row):
        field_dict = {
            "id": "%s%s%s" % (model_row.id, field_row.id, random.randint(1, 1000)),
            "name": field_row.name,
            "type": "string",
            "eval": False,
            "pattern": "",
            "expression": "",
            "showOnlyNameType": False,
            "testData": "1"
        }
        if field_row.ttype in ['boolean']:
            field_dict.update({'type': 'string'})
        elif field_row.ttype in ['integer']:
            field_dict.update({'type': 'number', "pattern": "#,##0"})
        elif field_row.ttype in ['float']:
            field_dict.update({'type': 'number', "pattern": "#,##0.00"})
        elif field_row.ttype in ['binary']:
            field_dict.update({'type': 'image'})
        elif field_row.ttype in ['many2one']:
            model_row_new = self.env['ir.model'].search([('model', '=', field_row.relation)])
            field_dict.update({'type': 'map'})
            if model_row_new:
                return self.get_new_model_row(field_row, model_row_new, model_row)
        elif field_row.ttype in ['one2many', 'many2many']:
            model_row_new = self.env['ir.model'].search([('model', '=', field_row.relation)])
            field_dict.update({'type': 'array'})
            if model_row_new:
                return_val = self.get_new_model_row(field_row, model_row_new, model_row)
                return_val.update({'type': 'array'})
                return return_val
        else:
            field_dict.update({'type': 'string'})
        return field_dict

    def get_new_model_row(self, field_parent_row, model_row, model_row_old):
        children = []
        for field_row in model_row.field_id:
            if field_parent_row.ttype in ('many2one', 'many2many', 'one2many') and field_row.name not in ['name', 'display_name']:
                continue
            children.append(self.get_field_dict(model_row, field_row))
        parameters = {
            "id": "%s%s%s" % (model_row.id, model_row_old.id, random.randint(1, 1000)),
            "name": field_parent_row.name,
            "type": "map",
            "eval": False,
            "pattern": "",
            "expression": "",
            "showOnlyNameType": False,
            "children": children
        }
        return parameters

    def get_all_model_row(self, model_row):
        children = []
        for field_row in model_row.field_id:
            children.append(self.get_field_dict(model_row, field_row))
        return children

    def get_all_parameters(self):
        parameters = [{
            "id": 6,
            "name": "page_count",
            "type": "number",
            "eval": False,
            "pattern": "",
            "expression": "",
            "showOnlyNameType": True,
            "testData": "1"
        }, {
            "id": 7,
            "name": "page_number",
            "type": "number",
            "eval": True,
            "pattern": "",
            "expression": "",
            "showOnlyNameType": True,
            "testData": "2"
        }]
        # company_row = self.env['ir.model'].search([('model', '=', 'res.company')])
        # parameters.append(self.get_all_model_row(company_row))
        if self.model_id:
            parameters.extend(self.get_all_model_row(self.model_id))
        return json.dumps(parameters)

    # def get_parameters(self):
    #     parameters = []
    #     if self.is_show_model:
    #         parameters.extend(self.get_all_parameters())
    #     else:
    #         parameters.extend(self.get_config_model_field)
    #     return parameters

    def get_all_report_data(self, report_id):
        report_row = self.env['report.bro'].sudo().browse(report_id)
        report_data = report_row.report_definition
        if not report_data:
            parameters = report_row.get_all_parameters()

            default_report_data = '''{
                "docElements": [],
                "parameters": %s,
                "styles": [],
                "version": 1,
                "documentProperties": {
                    "pageFormat": "%s",
                    "pageWidth": "",
                    "pageHeight": "",
                    "unit": "mm",
                    "orientation": "%s",
                    "contentHeight": "",
                    "marginLeft": "%s",
                    "marginTop": "%s",
                    "marginRight": "%s",
                    "marginBottom": "%s",
                    "header": %s,
                    "headerSize": "%s",
                    "headerDisplay": "%s",
                    "footer": %s,
                    "footerSize": "%s",
                    "footerDisplay": "%s",
                    "patternLocale": "en",
                    "patternCurrencySymbol": "€"
                    }
                }''' % (parameters, report_row['pageFormat'], report_row['orientation'],
                        report_row['marginLeft'], report_row['marginTop'], report_row['marginRight'],
                        report_row['marginBottom'], report_row['header'], report_row['headerSize'],
                        report_row['headerDisplay'], report_row['footer'], report_row['footerSize'],
                        report_row['footerDisplay'])
        return report_data or default_report_data, report_row.name

    def report_bro_save_edit_val(self, vals):
        vals = safe_eval(vals)
        report_row = self.env['report.bro'].sudo().browse(vals.get('report_id'))
        report_row.report_definition = vals.get('report_data')
        return {'data': True}
